package com.zangs.emqx_expand.framework.interceptor;

import com.zangs.emqx_expand.common.annotation.SignatureApi;
import com.zangs.emqx_expand.common.filter.RepeatedlyRequestWrapper;
import com.zangs.emqx_expand.common.utils.Signature;
import com.zangs.emqx_expand.common.utils.StringUtils;
import com.zangs.emqx_expand.system.domain.AppUser;
import com.zangs.emqx_expand.system.service.IAppUserService;
import com.zangs.emqx_expand.system.service.ISysConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.stream.Collectors;


@Component
public class SignInterceptor implements HandlerInterceptor {
    private static final Logger log = LoggerFactory.getLogger(SignInterceptor.class);

    private static final String appIdHeader = "appid";

    private static final String timestampHeader = "timestamp";

    private static final String signatureHeader = "signature";
    @Autowired
    private ISysConfigService sysConfigService;
    @Autowired
    private IAppUserService appUserService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 不是处理器方法，继续处理
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        String path = handlerMethod.getBeanType().getName() + "." + method.getName();
        // 方法上没有注解，继续处理
        if (!method.isAnnotationPresent(SignatureApi.class)) {
            return true;
        }
        SignatureApi annotation = method.getAnnotation(SignatureApi.class);
        String appId = request.getHeader(appIdHeader);
        AppUser appUser = validateAppIdAndUrl(response, appId, path);
        //查不到appid
        if (ObjectUtils.isEmpty(appUser)) {
            return false;
        }
        //需要签名校验和进行签名校验
        return !annotation.signature() || validateSignature(response, request, appUser);

    }


    /**
     * 验证appId存在且有该url权限
     *
     * @param response
     * @param appId
     * @param path
     * @return
     * @throws IOException
     */
    private AppUser validateAppIdAndUrl(HttpServletResponse response, String appId, String path) throws IOException {
        if (!StringUtils.hasText(appId)) {
            logErrorAndRespond(response, "appId必填!");
            return null;
        }
        //验证appId存在且有该url权限
        AppUser appUser = appUserService.selectAppUserByAppIdAndPath(appId, path);
        if (ObjectUtils.isEmpty(appUser)) {
            logErrorAndRespond(response, "appId没有该url权限!");
        }
        //验证是否过期
        Date expirationDate = appUser.getExpirationDate();
        if (!ObjectUtils.isEmpty(expirationDate) && expirationDate.before(new Date())) {
            logErrorAndRespond(response, "appId已过期!");
        }
        return appUser;


    }

    /**
     * 签名校验
     */
    private boolean validateSignature(HttpServletResponse response, HttpServletRequest request, AppUser appUser) throws IOException {
        String timestampStr = request.getHeader(timestampHeader);
        String signature = request.getHeader(signatureHeader);


        if (!StringUtils.hasText(timestampStr) || !StringUtils.hasText(signature)) {
            logErrorAndRespond(response, "时间戳和签名必填!");
            return false;
        }

        String url = request.getRequestURI();
        if (StringUtils.hasText(request.getQueryString())) {
            url += "?" + request.getQueryString();
        }

        String body = "";
        if (request instanceof RepeatedlyRequestWrapper) {
            RepeatedlyRequestWrapper cachedRequest = (RepeatedlyRequestWrapper) request;
            body = cachedRequest.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
        }
        if (!Signature.verify(appUser.getAppSecret(), url, body, timestampStr, signature)) {
            logErrorAndRespond(response, "签名错误!");
            return false;
        }
        if (sysConfigService.selectVerificationExpirationTime()) {
            long timestamp = Long.parseLong(timestampStr);
            long currentTimestamp = System.currentTimeMillis() / 1000;
            long timeDifferenceLimit = 10 * 60; // 10分钟

            if (Math.abs(timestamp - currentTimestamp) > timeDifferenceLimit) {
                logErrorAndRespond(response, "签名过期!");
                return false;
            }
        }


        return true;
    }


    private void logErrorAndRespond(HttpServletResponse response, String errorMessage) throws IOException {
        // 使用日志框架记录错误
        log.error(errorMessage);
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        response.setStatus(500);
        response.getWriter().println(errorMessage);
    }
}
